const Koa = require('koa');
const Router = require("@koa/router");
const { koaBody } = require('koa-body');
const parser = require("koa-bodyparser");
const cors = require('koa2-cors');
const koajwt = require('koa-jwt');
const static = require('koa-static');
const WebSocket = require('ws');
const path = require("path");
const fs = require("fs");

// 导入模块和工具
const modules = require('./routes/routes');
const { Group, User, Article, Editor, Publish, PublishComment, PublishLike } = require("./database/index");
const { ip, formatDate, parseObjectUrl, JWT_SECRET, PORT} = require('./untils');
const { webSocketCfg } = require("./untils/webSocketCfg");
const {initSuperAdmin} = require("./untils/common");

// -------------------------- 常量定义 --------------------------
const STATIC_DIR = path.join(__dirname, 'public'); // 静态文件目录
const UPLOAD_DIR = path.join(STATIC_DIR, 'uploads'); // 上传目录

// -------------------------- 应用初始化 --------------------------
const app = new Koa();
const router = new Router();

// 确保上传目录存在
if (!fs.existsSync(UPLOAD_DIR)) {
    fs.mkdirSync(UPLOAD_DIR, { recursive: true });
}

// -------------------------- 中间件配置 --------------------------

// 1. 错误处理中间件（必须放在最前面）
app.use(async (ctx, next) => {
    try {
        await next();
        console.log(`${formatDate(new Date())}：请求完成 - ${ctx.status} ${ctx.method} ${ctx.url}`)
    } catch (err) {
        // JWT认证错误处理
        if (err.status === 401) {
            ctx.status = 401;
            ctx.body = {
                code: 401,
                msg: '身份验证失败：' + (err.msg || '无效的令牌')
            };
        } else {
            // 其他错误处理
            ctx.status = err.status || 500;
            ctx.body = {
                code: ctx.status, // 修复原代码变量引用错误
                msg: err.message || '服务器内部错误'
            };
        }
        // 记录错误日志
        console.error(`${formatDate(new Date())}：请求错误 - ${err.message}`, err.stack);
    }
});

// 2. 跨域配置
app.use(cors({
    origin: ctx => "*", // 保持原有跨域策略
    maxAge: 5,
    credentials: true,
    allowMethods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
    allowHeaders: ["Content-Type", "Authorization", "Accept"],
    exposeHeaders: ["WWW-Authenticate", "Server-Authorization"]
}));

// 3. JWT验证（排除不需要验证的路径）
app.use(koajwt({ secret: JWT_SECRET }).unless({
    path: [
        /^\/user\/login/,
        /^\/proxy-api\/user\/login/,
        /^\/user\/logout/,
        /^\/user\/addUser/,
        /^\/test/,
        /^\/toAdmin/,
        /^\/admin.html/,
        /^\/downloadExcel/,
        /^\/uploadFile/,
        /^\/verify/,
        /^\/uploads/,
        /^\/defaultImgs/,
        /^ws/ // WebSocket
    ]
}));

// 4. 静态文件服务
app.use(static(STATIC_DIR));

// 5. 文件上传配置
app.use(koaBody({
    multipart: true,
    maxFileSize: 1000 * 1024 * 1024, // 1000MB
    formidable: {
        uploadDir: UPLOAD_DIR,
        keepExtensions: true,
        onFileBegin: (name, file) => {
            // 确保上传目录存在（双重保障）
            if (!fs.existsSync(UPLOAD_DIR)) {
                fs.mkdirSync(UPLOAD_DIR, { recursive: true });
            }
        },
        onError: (err) => {
            console.error(`${formatDate(new Date())}：上传错误：${err.message}`);
        }
    }
}));

// 6. 请求体解析
app.use(parser());

// -------------------------- 路由注册 --------------------------
for (const route of modules) {
    switch (route.type) {
        case 'get':
            router.get(route.url, route.method);
            break;
        case 'post':
            router.post(route.url, route.method);
            break;
        default:
            console.warn(`${formatDate(new Date())}：未支持的请求方法: ${route.type}, 路径: ${route.url}`);
    }
}
app.use(router.routes());
app.use(router.allowedMethods()); // 处理405和501错误

// -------------------------- 数据库表同步 --------------------------
async function syncDatabase() {
    try {
        // 按依赖反向顺序同步（先删除关联表，再删除主表）
        // 关联最深的表放在最前面
        await Group.sync({ force: false });
        await User.sync({ force: false });
        await Article.sync({ force: false }); // 依赖Group
        await Publish.sync({ force: false }); // 依赖User
        await PublishComment.sync({ force: false }); // 依赖Publish、User
        await PublishLike.sync({ force: false });    // 依赖Publish、User
        await Editor.sync({ force: false });
        console.log(`${formatDate(new Date())}：所有数据库表创建/连接成功`);
        await initSuperAdmin()
    } catch (error) {
        console.error(`${formatDate(new Date())}：数据库表同步失败：`, error);
    }
}

// -------------------------- WebSocket配置 --------------------------
function initWebSocket(server) {
    const wss = new WebSocket.Server({ server });

    wss.on('listening', () => {
        console.log(`${formatDate(new Date())}：WebSocket server is listening on port ${PORT}`);
    });

    // 跨域头配置
    wss.on('headers', (headers, req) => {
        if (req.origin) {
            headers['Access-Control-Allow-Origin'] = req.origin;
            headers['Access-Control-Allow-Credentials'] = 'true';
        }
    });

    wss.on('connection', async (ws, req) => {
        console.log(`${formatDate(new Date())}：WebSocket 已连接`);
        try {
            const { url } = req;
            const urlObj = parseObjectUrl(url);
            console.log(`${formatDate(new Date())}：WebSocket url参数`, urlObj);

            // 确保操作类型存在
            if (!webSocketCfg[urlObj.opType]) {
                throw new Error(`未定义的WebSocket操作类型：${urlObj.opType}`);
            }

            // 执行对应操作的生命周期方法
            await webSocketCfg[urlObj.opType].connectionFn(wss, WebSocket, urlObj);

            ws.on('message', async (msg) => {
                await webSocketCfg[urlObj.opType].messageFn(wss, WebSocket, urlObj, msg);
            });

            ws.on('close', async () => {
                await webSocketCfg[urlObj.opType].closeFn(wss, WebSocket, urlObj);
            });

        } catch (error) {
            console.error(`${formatDate(new Date())}：WebSocket连接处理错误：`, error);
            ws.close(1011, '服务器内部错误');
        }
    });

    return wss;
}

// -------------------------- 启动服务器 --------------------------
async function startServer() {
    try {
        // 先同步数据库
        await syncDatabase();

        // 启动HTTP服务器
        const server = app.listen(PORT);
        console.log(`${formatDate(new Date())}：服务器启动成功，端口：${PORT}, 测试地址：http://${ip}:${PORT}/test`);

        // 初始化WebSocket
        initWebSocket(server);

    } catch (error) {
        console.error(`${formatDate(new Date())}：服务器启动失败：`, error);
        process.exit(1); // 启动失败退出进程
    }
}

// 启动应用
startServer();
